- Published on
solidity
- Authors
- Name
- JiGu
- @crypto20x
https://remix.ethereum.org/ 在线调试IDE--remix
合约基本结构
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract Quiz1{
// add something here
string public _string = "WTF";
}
值类型
Boolean布尔型
bool public _bool = true;
Integers整型
int public _int = -1;
uint public _uint = 1;
uint256 public _number = 210980123;
int和uint和存储整型,最多存储256位即32字节的数据。
Address地址类型
address存储20bytes(40位十六进制数,160bit)的以太坊地址。 address payable与address相同,不过它具有两个成员函数,transfer和send,用来转移ETH。
address public addr1 = 0x1234567890123456789012345678901234567890;
address public addr2 = address(0x123);
address payable public _payable = payable(addr1);
function getBalance(address _addr) public view returns (uint256) {
return _addr.balance;
}
// 向_payabled地址转入1Wei
// 如果不加require判断,msg.value不管多大,剩余的都会转入合约地址,需要合约做退款处理
function trans() public payable {
require(msg.value >= 1, "Please enter a right vale");
_payable.transfer(1);
}
Fixed-size byte arrays定长字节数组
字节数组类型包括 bytes1,bytes8,bytes32 等等,最大的是bytes32即256bit。
bytes则是动态大小的字节数组。与string的主要区别是,string存的是utf字符串,bytes是字节数据。
bytes32 public _byte32 = "dd";
bytes4 public _byte = 0x01010101;
bytes1 public _bytes1 = _byte32[0];
bytes public _bytes = "123123123";
bytes public _bytes2 = hex"fe132131";
函数
function <function name>(<parameter types>) [internal|external] [pure|view|payable] [returns (<return types>)]
可见性修饰符
- 函数需指定可见性,没有默认值
- private,只能从内部访问,不能继承。
- external,只能被外部合约访问,不过可以通过this.f()被内部调用,处理大型数据结构更省gas,因为数据不会被复制到内存中。
- internal,只能被内部访问,可以继承。
- public,private,internal还可以修饰状态变量,public变量会自动生成同名的getter函数。
- 状态变量默认的可见性为internal
行为修饰符
当函数被定义为payable时,可以通过msg.value发送ETH。
pure 意味着纯计算函数,没有更改合约内部变量,也没有读取。
view 可以理解为只读,读取了合约内部状态,包括变量,全局变量。
pure和view从外部调用时,不消耗gas,合约内部调用会消耗gas。
返回值
返回多个值
function returnValues() pure public returns(uint, address, uint[3] memory) {
return (1, address(0x123),[uint(1),2,3]);
}
存储位置
有三种存储位置,分别是storage,memory和calldata。
storage存储在链上类似硬盘,memory和calldata类似内存,临时存储在内存中。
创建引用时,storage的引用会改变原数组,memory不会改变原数组。
int[] public storageVar = [int(0),1,3,4];
function testStorage() public returns(int[] memory, int[] memory) {
int[] storage _storageVar = storageVar; //创建一个storage的引用,跟直接用全局变量没区别。
_storageVar[0] = 100;
storageVar[1] = 200;
int[] memory _memoryVar = storageVar; //直接拷贝了一份到
_memoryVar[2] = 300;
return (_storageVar, _memoryVar);
}
storage
状态变量默认就是storage类型的,储存在链上。
memory
函数的参数和临时变量一般都是memory
calldata
calldata与memory很像,都不存在链上,但是calldata不能修改,一般用于函数参数。
function testCalldata(string[] calldata a) public pure returns(string[] calldata){
// cant modify, unless is a memory variable
//a[0] = "a";
return a;
}
变量作用域
状态变量 State variable
类似其他语言中的全局变量
contract MyVariable{
uint public score = 999;
string public name = "Meow";
string public solgan = "Make America meow again!";
}
局部变量 Local variable
跟其他语言中的局部变量类似,在函数中定义,作用域就只在函数中。
全局变量 Global variable
英文叫全局变量,感觉更像环境变量,在整个evm环境中存在的变量。或者说它的全局范围在整个evm中。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GlobalVariablesGetter {
struct GlobalVars {
uint256 blockNumber;
uint256 blockTimestamp;
uint256 blockChainid;
address blockCoinbase;
uint256 blockDifficulty;
uint256 blockPrevrandao;
uint256 blockGaslimit;
address msgSender;
uint256 msgValue;
uint256 txGasprice;
address txOrigin;
uint256 gasLeft;
uint256 thisBalance;
}
function getGlobalVariables() public payable returns (GlobalVars memory) {
return GlobalVars({
blockNumber: block.number,
blockTimestamp: block.timestamp,
blockChainid: block.chainid,
blockCoinbase: block.coinbase,
blockDifficulty: block.difficulty,
blockPrevrandao: block.prevrandao,
blockGaslimit: block.gaslimit,
msgSender: msg.sender,
msgValue: msg.value,
txGasprice: tx.gasprice,
txOrigin: tx.origin,
gasLeft: gasleft(),
thisBalance: address(this).balance
});
}
function getTypeInfo() public pure returns (uint256, uint256, int256, int256) {
return (
type(uint256).min,
type(uint256).max,
type(int256).min,
type(int256).max
);
}
}
block.difficulty 在转PoS后已经被 block.prevrandao 替代了,返回的是beacon chain随机数,在remix的vm里不存在。
Array 数组
分为定长数组,和可变数组。 定长数组,通过下标赋值,可变数组通过push,pop赋值。
而局部变量的数组,必须定义成memory,而且需指定长度。
通过length方法可以得到数组的长度。
// SPDX-License-Identifier: MyRule
pragma solidity ^0.8.0;
contract Array {
//Fixed Array
uint[3] public _uintArr;
address[100] public _addrArr;
//variable-length Array
uint[] public _uintArr2;
address[] public _addrArr2;
bytes public _bytesArr;
bytes1[] public _bytes1Arr;
function testArray() public {
_uintArr[0] = 1;
_addrArr[0] = address(0x1);
_uintArr2.push(1);
_addrArr2.push(address(0x2));
_bytesArr.push(0x12);
uint[] memory tmp_uint_arr = new uint[](5);
tmp_uint_arr[0] = 1;
uint[5] memory tmp_uint_arr2;
tmp_uint_arr2[0] = 1;
}
}
Eample Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract Mytest{
// add something here
bool public _bool = true;
int16 public _int16 = 9999;
string public _string = "hello";
bytes public _bytes = hex"feab0123";
bytes32 public _byte32 = "dd";
bytes1 public _byte1 = _byte32[0];
address public _address = address(0x123);
address payable public _payable = payable(0x0);
// make DirectionSet contain East, South, West, North.
enum DirectionSet {East, South, West, North}
function trans() public payable {
require(msg.value >= 1, "Please send enough ETH");
_payable.transfer(1);
}
function transWithRefund() public payable {
require(msg.value >= 1, "Please send enough ETH");
if(msg.value > 1){
payable(msg.sender).transfer(msg.value - 1);
}
_payable.transfer(1);
}
function getEnumDirectionSet() public pure returns (DirectionSet) {
return DirectionSet.North;
}
function getBalance() public view returns (uint256) {
return _payable.balance;
}
function getContractBalance() public view returns (uint256) {
return address(this).balance;
}
function returnValues() pure public returns(uint, address, uint[3] memory) {
return (1, address(0x123),[uint(1),2,3]);
}
function testCalldata(string[] calldata a) public pure returns(string[] calldata){
// cant modify, unless is a memory variable
//a[0] = "a";
return a;
}
int[] public storageVar = [int(0),1,3,4];
function testStorage() public returns(int[] memory, int[] memory) {
int[] storage _storageVar = storageVar; //创建一个storage的引用,跟直接用全局变量没区别。
_storageVar[0] = 100;
storageVar[1] = 200;
int[] memory _memoryVar = storageVar; //直接拷贝了一份到
_memoryVar[2] = 300;
return (_storageVar, _memoryVar);
}
}